#!/bin/sh
#
# $FreeBSD$
#

# PROVIDE: ix-nginx
# REQUIRE: ix-warden
# BEFORE: nginx django

. /etc/rc.freenas


NGINX_PLUGINS_CONF="${HTTPDDIR}/plugins.conf"
NGINX_FASTCGI_PARAMS="${HTTPDDIR}/fastcgi_params"

get_ssl_certificate_name()
{
	${FREENAS_SQLITE_CMD} ${RO_FREENAS_CONFIG} "
	SELECT
		sc.cert_name
	FROM
		system_settings
	LEFT OUTER JOIN
		system_certificate as sc
	ON
		(stg_guicertificate_id = sc.id)
	ORDER BY
		-system_settings.id
	LIMIT
		1
	"
}

get_ssl_certificate()
{
	local certname

	certname="$(get_ssl_certificate_name)"
	if [ -n "${certname}" ]
	then
		echo "${SSLDIR}/${certname}.crt"
	fi
}

get_ssl_privatekey()
{
	local certname

	certname="$(get_ssl_certificate_name)"
	if [ -n "${certname}" ]
	then
		echo "${SSLDIR}/${certname}.key"
	fi
}

generate_plugins_conf()
{
	local IFS="|"
	local nginx_location

	: > "${NGINX_PLUGINS_CONF}"

        # Workaround: config check fail if it doesnt exist
        mkdir -p /var/tmp/nginx 2> /dev/null > /dev/null

	${FREENAS_SQLITE_CMD} ${RO_FREENAS_CONFIG} "
	SELECT
		id,
		plugin_name,
		plugin_jail,
		plugin_enabled,
		plugin_port,
		plugin_path

	FROM
		plugins_plugins

	ORDER BY
		-id
	" | \
	while read -r id name jail enabled port ppath
	do
		local ipv4=$(jail_get_ipv4 "${jail}")
		local ipv6=$(jail_get_ipv6 "${jail}")
		local jpath=$(jail_get_path "${jail}")
		local ip=

		#
		# Default to IPv4 now if it exists, I'm unsure if
		# this will work with IPv6, needs testing.
		#
		if [ -n "${ipv4}" ]
		then
			jail_get_ip_and_netmask "${ipv4}"
			ip="${JIP}"

		elif [ -n "${ipv6}" ]
		then
			jail_get_ip_and_netmask "${ipv6}"
			ip="${JIP}"
		fi

		if [ -z "${name}" -o -z "${ip}" -o -z "${ppath}" ]
		then
			continue
		fi

		cat<<-__EOF__>>"${NGINX_PLUGINS_CONF}"
		location ~ '/plugins/${name}/${id}/' {
		    fastcgi_pass   ${ip}:${port};
		    include		fastcgi_params;
		    root ${ppath};
__EOF__

		nginx_location="${jpath}/${ppath}/nginx_location"
		if [ -f ${nginx_location} ]; then
			tmp=$(mktemp -t nginx)
			echo "
			events {}
			http {
				server {
					location / {
						$(cat ${nginx_location})
					}
				}
			}
			" > ${tmp}
			${HTTPD} -t -c ${tmp} 2> /dev/null > /dev/null
			if [ $? -eq 0 ]; then
				sed "s/%%PLUGIN_ID%%/${id}/g" ${nginx_location} >> "${NGINX_PLUGINS_CONF}"
			fi

		fi

		cat<<-__EOF__>>"${NGINX_PLUGINS_CONF}"
		}
__EOF__

	done
}


generate_nginx_conf()
{
	local res=1
	local proto="${1}"
	local addr="${2}"
	local addr6="${3}"
	local port="${4}"
	local httpsport="${5}"
	local httpsredirect="${6}"
	local vcenter_https="${7}"
	local working_ssl=false
	local default_ui="ui"
	local dhparams_file="/data/dhparam.pem"
	local dojo=$(env PYTHONPATH=/usr/local/www/freenasUI/ /usr/local/bin/python -B -S -c 'import settings; print(settings.DOJANGO_DOJO_VERSION)')

	[ -s /data/dhparam.pem ] || openssl dhparam -rand - 2048 > /data/dhparam.pem
	[ -s /data/dhparam1024.pem ] || openssl dhparam -rand - 1024 > /data/dhparam1024.pem

	if [ "${vcenter_https}" = "1" ]; then
		dhparams_file="/data/dhparam1024.pem"
	fi

	{
	cat << __EOF__
#
#    FreeNAS nginx configuration file
#

load_module /usr/local/libexec/nginx/ngx_http_uploadprogress_module.so;

user www www;
worker_processes  1;

events {
    worker_connections  1024;
}

http {
    include       mime.types;
    default_type  application/octet-stream;

    # reserve 1MB under the name 'proxied' to track uploads
    upload_progress proxied 1m;

    sendfile        on;
    #tcp_nopush     on;
    client_max_body_size 800m;

    #keepalive_timeout  0;
    keepalive_timeout  65;

    # Disable tokens for security (#23684)
    server_tokens off;

    #gzip  on;
    #upload_store /var/tmp/firmware;
    client_body_temp_path /var/tmp/firmware;

    error_log syslog:server=unix:/var/run/log,nohostname;
    access_log syslog:server=unix:/var/run/log,nohostname;

    upstream netdata {
        # the netdata server
        server 127.0.0.1:19999;
        keepalive 64;
    }

    
    server {
        server_name  localhost;
__EOF__

	if [ "${proto}" = "https" -o "${proto}" = "httphttps" ]; then
                local httpdcert="$(get_ssl_certificate)"
                local httpdkey="$(get_ssl_privatekey)"

		local validcert=0
		${OPENSSL} x509 -in "${httpdcert}" -noout -text -dates -purpose > /dev/null 2>&1
		let "validcert |= $?" > /dev/null
		${OPENSSL} rsa -in "${httpdkey}" -check -noout > /dev/null 2>&1
		let "validcert |= $?" > /dev/null
		# Checking if the key bit lenght is greater than or equal to 1024
		local safecert=$(${OPENSSL} rsa -in "${httpdkey}" -text -noout | grep "Private-Key" | egrep -o '[0-9]' | tr -d "\n")

		if [ ${validcert} -eq 0 -a ${safecert} -ge 1024 ]; then
			working_ssl=true
			# Delete this file (if it exists) now that we have a valid cert (else the alert ui keeps complaining)
			if [ -f /tmp/alert_invalid_ssl_nginx ]; then
			    rm /tmp/alert_invalid_ssl_nginx
			fi

			cat << __EOF__
	listen			${addr}:${httpsport} default_server ssl http2;
	listen			[${addr6}]:${httpsport} default_server ssl http2;

	ssl_certificate		"${httpdcert}";
	ssl_certificate_key	"${httpdkey}";
	ssl_dhparam "${dhparams_file}";

	ssl_session_timeout	120m;
	ssl_session_cache	shared:ssl:16m;

        ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
	ssl_prefer_server_ciphers on;
	ssl_ciphers EECDH+ECDSA+AESGCM:EECDH+aRSA+AESGCM:EECDH+ECDSA+SHA256:EDH+aRSA:EECDH:!RC4:!aNULL:!eNULL:!LOW:!3DES:!MD5:!EXP:!PSK:!SRP:!DSS;
	add_header Strict-Transport-Security max-age=31536000;

	## TODO: OCSP Stapling
	#ssl_stapling on;
	#ssl_stapling_verify on;
	#resolver ${resolver};
	#ssl_trusted_certificate ${ca_chain};
__EOF__
		else
			port=80
			touch /tmp/alert_invalid_ssl_nginx
			# The below to inform the user why his cert was invalidated (if it was invalidated on the basis of key length)
			if [ ${safecert} -lt 1024 ]; then
			    echo "${safecert}" > /tmp/alert_invalid_ssl_nginx
			fi
		fi
	fi

	if [ ! ${working_ssl} -o "${proto}" = "http" -o "${proto}" = "httphttps" ]; then
		echo "        listen       ${addr}:${port};"
		echo "        listen       [${addr6}]:${port};"
	fi

	if ! is_freenas; then
		default_ui="legacy"
	fi

	cat << __EOF__

        location / {
            rewrite ^.* /${default_ui}/;
        }

        location ~ /(legacy|plugins|api/v1.0)/ {
            include fastcgi_params;
            fastcgi_pass 127.0.0.1:9042;
            fastcgi_pass_header Authorization;
            fastcgi_intercept_errors off;
            fastcgi_read_timeout 600m;
            #fastcgi_temp_path /var/tmp/firmware;
            fastcgi_param HTTPS \$https;

            # track uploads in the 'proxied' zone
            # remember connections for 30s after they finished
            track_uploads proxied 30s;
        }

        location /progress {
            # report uploads tracked in the 'proxied' zone
            report_uploads proxied;
        }

        location ^~ /legacy/static {
            alias /usr/local/www/freenasUI/static;
            add_header Cache-Control "must-revalidate";
            add_header Etag "$(cat /etc/version)";
        }

        location ^~ /legacy/dojango/dojo-media/release/${dojo} {
            alias /usr/local/www/dojo;
        }

        location /api/docs {
            proxy_pass http://127.0.0.1:6000/api/docs;
            proxy_set_header Host \$host;
            proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
            proxy_set_header X-Scheme \$scheme;
            proxy_set_header X-Script-Name /api/docs;
        }

        location /api/docs/restful/static {
            alias /usr/local/www/swagger-ui/node_modules/swagger-ui-dist;
        }

        location /docs {
            alias /usr/local/www/data/docs;
        }

        location /docs_legacy {
            alias /usr/local/www/data/docs_legacy;
        }

        location /ui {
            try_files \$uri \$uri/ /index.html =404;
            alias /usr/local/www/webui;
        }

        location /netdata {
            return 301 /netdata/;
        }

       location ~ ^/netdata/(?<ndpath>.*) {
            proxy_redirect off;
            proxy_set_header Host \$host;

            proxy_set_header X-Forwarded-Host \$host;
            proxy_set_header X-Forwarded-Server \$host;
            proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
            proxy_http_version 1.1;
            proxy_pass_request_headers on;
            proxy_set_header Connection "keep-alive";
            proxy_store off;
            proxy_pass http://netdata/\$ndpath\$is_args\$args;

            gzip on;
            gzip_proxied any;
            gzip_types *;
        }

        location /websocket {
            proxy_pass http://127.0.0.1:6000/websocket;
            proxy_http_version 1.1;
            proxy_set_header X-Real-Remote-Addr \$remote_addr;
            proxy_set_header X-Real-Remote-Port \$remote_port;
            proxy_set_header Upgrade \$http_upgrade;
            proxy_set_header Connection "upgrade";
        }

        location /websocket/shell {
            proxy_pass http://127.0.0.1:6000/_shell;
            proxy_http_version 1.1;
            proxy_set_header X-Real-Remote-Addr \$remote_addr;
            proxy_set_header X-Real-Remote-Port \$remote_port;
            proxy_set_header Upgrade \$http_upgrade;
            proxy_set_header Connection "upgrade";
            proxy_send_timeout 7d;
            proxy_read_timeout 7d;
        }

        location /api/v2.0 {
	    # do not add the path to proxy_pass because of automatic url decoding
	    # e.g. /api/v2.0/pool/dataset/id/tank%2Ffoo/ would become
	    #      /api/v2.0/pool/dataset/id/tank/foo/
            proxy_pass http://127.0.0.1:6000;
            proxy_http_version 1.1;
            proxy_set_header X-Real-Remote-Addr \$remote_addr;
            proxy_set_header X-Real-Remote-Port \$remote_port;
            proxy_set_header Host \$host;
            proxy_set_header X-Forwarded-For \$remote_addr;
        }

        location /_download {
            proxy_pass http://127.0.0.1:6000;
            proxy_http_version 1.1;
            proxy_set_header X-Real-Remote-Addr \$remote_addr;
            proxy_set_header X-Real-Remote-Port \$remote_port;
        }

        location /_upload {
            # Allow uploads of any size. Its middlewared job to handle size.
            client_max_body_size 0;
            proxy_pass http://127.0.0.1:6000;
            # make sure nginx does not buffer the upload and pass directly to middlewared
            proxy_request_buffering off;
            proxy_http_version 1.1;
            proxy_set_header X-Real-Remote-Addr \$remote_addr;
            proxy_set_header X-Real-Remote-Port \$remote_port;
        }

        location /images {
            alias /var/db/system/webui/images;
        }

        #error_page  404              /404.html;

        # redirect server error pages to the static page /50x.html
        #
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   /usr/local/www/nginx-dist;
        }

        #include plugins.conf;
    }
__EOF__

	if [ "${proto}" = "https" -a "${working_ssl}" = true -a "${httpsredirect}" = "1" ]; then
		cat << __EOF__
    server {
	listen ${addr}:80;
	listen [${addr6}]:80;
	server_name localhost;
	return 307 https://\$host:${httpsport}\$request_uri;
    }
__EOF__
	fi

	echo "}";

	} > ${HTTPDCONF}

	if [ ! -d "/var/log/nginx" ]; then
		mkdir -p /var/log/nginx
	fi

}


set_stg_guiprotocol()
{
	local res=1
	local proto="${1}"

	if [ "${proto}" = "http" -o "${proto}" = "https" -o "${proto}" = "httphttps" ]
	then
		${FREENAS_SQLITE_CMD} ${RO_FREENAS_CONFIG} "
		UPDATE
			system_settings
		SET
			stg_guiprotocol = '${proto}'
		"
		res=$?
	fi

	return ${res}
}


set_stg_guiport()
{
	local res=1
	local port="${1}"

	: $((port += 0))

	${FREENAS_SQLITE_CMD} ${RO_FREENAS_CONFIG} "
	UPDATE
		system_settings
	SET
		stg_guiport = '${port}'
	"
	res=$?

	return ${res}
}


generate_fastcgi_params()
{
	local IFS="|"

	${FREENAS_SQLITE_CMD} ${RO_FREENAS_CONFIG} "
	SELECT
		stg_guiprotocol

	FROM
		system_settings

	ORDER BY
		-id

	LIMIT 1
	" | \
	while read stg_guiprotocol
	do
		local ssl_enable=0

		stg_guiprotocol=$(echo "${stg_guiprotocol}"|tr a-z A-Z)
		case "${stg_guiprotocol}" in
			HTTP) ssl_enable=0; ;;
			HTTPS) ssl_enable=1; ;;
		esac

		local tmp="$(mktemp /tmp/tmp.XXXXXX)"
		grep -Eiv '^( |\t)*fastcgi_param( |\t)+https( |\t)+' \
			< "${NGINX_FASTCGI_PARAMS}" > "${tmp}"

		if [ "${ssl_enable}" = "1" ]
		then
			echo "fastcgi_param HTTPS on;" >> "${tmp}"
		fi
		mv "${tmp}" "${NGINX_FASTCGI_PARAMS}"
	done
}


get_nginx_settings()
{
	local settings=$(
		local IFS="|"
		${FREENAS_SQLITE_CMD} ${RO_FREENAS_CONFIG} "
		SELECT
			stg_guiprotocol,
			stg_guiaddress,
			stg_guiv6address,
			stg_guiport,
			stg_guihttpsport,
			stg_guihttpsredirect

		FROM
			system_settings

		ORDER BY
			-id

		LIMIT 1
		" | \
		while read -r stg_guiprotocol stg_guiaddress stg_guiv6address stg_guiport stg_guihttpsport stg_guihttpsredirect
		do
			echo "${stg_guiprotocol}|${stg_guiaddress}|${stg_guiv6address}|${stg_guiport}|${stg_guihttpsport}|${stg_guihttpsredirect}"
		done
	)

	local proto=$(echo ${settings}|cut -f1 -d"|" -s|tr A-Z a-z)
	local addr=$(echo ${settings}|cut -f2 -d"|" -s)
	local addr6=$(echo ${settings}|cut -f3 -d"|" -s)
	local port=$(echo ${settings}|cut -f4 -d"|" -s)
	local httpsport=$(echo ${settings}|cut -f5 -d"|" -s)
	local httpsredirect=$(echo ${settings}|cut -f6 -d"|" -s)

	: ${proto:="http"}
	: ${addr:="0.0.0.0"}
	: ${addr6:="::"}

	if [ -z "${httpsport}" ]
	then
		httpsport="443"
	fi
	if [ -z "${port}" ]
	then
		port="80"
	fi

	if [ "${addr}" != "0.0.0.0" -a \
		-z "$(/sbin/ifconfig -a|grep ${addr})" ]; then
		addr="0.0.0.0"
	fi

	if [ "${addr6}" != "::" -a \
		-z "$(/sbin/ifconfig -a|grep ${addr6})" ]; then
		addr6="::"
	fi

	echo "${proto}|${addr}|${addr6}|${port}|${httpsport}|${httpsredirect}"
}


ix_nginx_start()
{
	RO_FREENAS_CONFIG=$(ro_sqlite ${name} 2> /tmp/${name}.fail && rm /tmp/${name}.fail)
	trap 'rm -f ${RO_FREENAS_CONFIG}' EXIT

	local settings=$(get_nginx_settings)

	local proto=$(echo "${settings}"|cut -f1 -d"|")
	local addr=$(echo "${settings}"|cut -f2 -d"|")
	local addr6=$(echo "${settings}"|cut -f3 -d"|")
	local port=$(echo "${settings}"|cut -f4 -d"|")
	local httpsport=$(echo "${settings}"|cut -f5 -d"|")
	local httpsredirect=$(echo "${settings}"|cut -f6 -d"|")

	local vcenter_https=$(
		${FREENAS_SQLITE_CMD} ${RO_FREENAS_CONFIG} "
		SELECT
			vc_enable_https

		FROM
			vcp_vcenterauxsettings

		ORDER BY
			-id
		"
	)


	#generate_plugins_conf
	#generate_fastcgi_params

	generate_nginx_conf "${proto}" "${addr}" "${addr6}" "${port}" "${httpsport}" "${httpsredirect}" "${vcenter_https}"

}


name="ix-nginx"
start_cmd='ix_nginx_start'
stop_cmd=':'
            
load_rc_config $name
run_rc_command "$1"
